package cn.com.yang.egg;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * @Author 杨亿金
 * @Date 2022/1/13 23:35
 * @CopyRight
 * @Version
 */
/***
 * Unsafe会报错
 * Eclipse中有一种叫做存取限制的机制，来防止你错误使用那些非共享的API。
 * 通常来说，Eclipse做的是对的，因为两点，我们不想要使用非共享API的，而且Eclipse知道什么是共享的和非共享的API。
 * 但是有时我们想要使用非共享的API，比如说用gmail的来发送和接收邮件，要用到SSL。
 * 这个就是非共享的API。这时候我们就要更改一些设置了。
 * 更改的步骤如下：
 * window-java-compiler-Error/Warning-Deprecated and Restricted API-Forbidden reference那里，设置成Ignore即可。
 * @author yangyijin
 *
 */
public class UnsafeDemo {
    static Unsafe unsafe;
    //static long offset;
    public volatile long result = 0;
    public int[] arr= {1,2,3,4,5,6};
    static {
        try {
            //获取成员变量
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            //设置可访问
            field.setAccessible(true);
            unsafe= (Unsafe) field.get(null);
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        }catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        UnsafeDemo unsafeDemo = new UnsafeDemo();
        try{
            long offset =unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("result"));
            for (int i = 0; i < 1000; i++) {
                unsafe.getAndAddLong(unsafeDemo,offset,i);
            }
            System.out.println(unsafeDemo.result);
            System.out.println(unsafe.arrayBaseOffset(unsafeDemo.arr.getClass()));
            System.out.println(unsafe.arrayIndexScale(unsafeDemo.arr.getClass()));
            unsafe.putOrderedLong(unsafeDemo,offset,5000);
            System.out.println(unsafeDemo.result);
            unsafe.putOrderedLong(unsafeDemo,offset,5050);
            System.out.println(unsafeDemo.result);
            Thread thread = new Thread(){
                @Override
                public void run() {
                    System.out.println("线程1开始沉睡");
                    long start = System.currentTimeMillis();
                    long end = System.currentTimeMillis()+8000;
                    unsafe.park(true,end);
                    System.out.println("主线程在"+(System.currentTimeMillis()-start)+"ms后唤醒");
                }
            };
            Thread son = new Thread(){

                @Override
                public void run() {
                    try {
                        System.out.println("线程2开始运行");
                        sleep(3000);
                        unsafe.unpark(thread);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();
            son.start();
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
